package api_services

import (
	"context"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/models/repo"
	DevcontainersVO "code.gitea.io/gitea/routers/api/devcontainer/vo"
	gitea_web_context "code.gitea.io/gitea/services/context"
	DevcontainersService "code.gitea.io/gitea/services/devstar_devcontainer"
	devcontainer_service_errors "code.gitea.io/gitea/services/devstar_devcontainer/errors"
	devcontainer_service_options "code.gitea.io/gitea/services/devstar_devcontainer/options"
)

// OpenDevcontainerAPIService  API 专用获取 DevContainer Service
func OpenDevcontainerAPIService(ctx *gitea_web_context.Context, opts *devcontainer_service_options.AbstractOpenDevcontainerOptions) (*DevcontainersVO.RepoDevContainerVO, error) {
	// 0. 检查用户传入参数
	if ctx == nil || opts == nil || opts.Actor == nil || opts.RepoId <= 0 {
		return nil, devcontainer_service_errors.ErrIllegalParams{
			FieldNameList: []string{"ctx", "opts", "opts.Actor", "opts.RepoId"},
		}
	}

	var devcontainerDetails DevcontainersVO.RepoDevContainerVO

	// 1. 开启数据库事务，查询 某用户在某仓库的 DevContainer
	errTxn := db.WithTx(ctx, func(ctx context.Context) error {
		// 1.1 调用 model层，查询数据库，将 repoId 变换为 Repository 对象
		repositoryInDB, err := repo.GetRepositoryByID(ctx, opts.RepoId)
		if err != nil || repositoryInDB == nil {
			return devcontainer_service_errors.ErrIllegalParams{
				FieldNameList: []string{"opts.RepoId"},
			}
		}

		// 1.2 检查该用户在该仓库 是否已经创建过 DevContainer
		optsRepoDevcontainer := &DevcontainersVO.RepoDevcontainerOptions{
			Actor:      opts.Actor,
			Repository: repositoryInDB,
		}
		devcontainerDetails, err = DevcontainersService.GetRepoDevcontainerDetails(ctx, optsRepoDevcontainer)
		if err != nil || devcontainerDetails.DevContainerId <= 0 {
			return devcontainer_service_errors.ErrDevcontainerNotFound{
				Actor:      opts.Actor,
				Repository: repositoryInDB,
			}
		}

		// 1.3 查询 DevContainer 成功，结束数据库事务
		return nil
	})
	if errTxn != nil {
		return nil, errTxn
	}

	// 2. 调用抽象层获取 DevContainer 最新状态（需要根据用户传入的 wait 参数决定是否要阻塞等待 DevContainer 就绪）
	optsOpenDevcontainer := &devcontainer_service_options.OpenDevcontainerAppDispatcherOptions{
		Name: devcontainerDetails.DevContainerName,
		Port: devcontainerDetails.DevContainerPort,
		Wait: opts.Wait,
	}

	openDevcontainerAbstractAgentVO, err := DevcontainersService.OpenDevcontainerService(ctx, optsOpenDevcontainer)
	if err != nil {
		return nil, err
	}

	// 3. 更新VO，合并成为真正的 SSH连接信息
	devcontainerDetails.DevContainerPort = openDevcontainerAbstractAgentVO.NodePortAssigned
	return &devcontainerDetails, nil
}
